using System;
using System.Collections.Generic;
using System.Diagnostics.Contracts;
using System.Linq;
using System.Linq.Expressions;

namespace Charisma
{
    [ContractClass(typeof (IRepositoryContract<>))]
    public interface IRepository<T> : IRepository where T : class
    {
        IQueryable<T> All { get; }

        T Find(object key);

        void Add(T item);

        void Add(IEnumerable<T> items);

        void Remove(T item);

        void Update(T item);

        void Update(T item, params Expression<Func<T, object>>[] fields);
    }

    [ContractClassFor(typeof (IRepository<>))]
    internal abstract class IRepositoryContract<T> : IRepository<T> where T : class
    {
        #region IRepository<T> Members

        Type IRepository.ElementType
        {
            get { return null; }
        }

        IQueryable<T> IRepository<T>.All
        {
            get
            {
                Contract.Ensures(Contract.Result<IQueryable<T>>() != null);
                return null;
            }
        }

        T IRepository<T>.Find(object key)
        {
            Contract.Requires(key != null);
            return default(T);
        }

        void IRepository<T>.Add(T item)
        {
            Contract.Requires(item != null);
        }

        void IRepository<T>.Add(IEnumerable<T> items)
        {
            Contract.Requires(items != null);
        }

        void IRepository<T>.Remove(T item)
        {
            Contract.Requires(item != null);
        }

        void IRepository<T>.Update(T item)
        {
            Contract.Requires(item != null);
        }

        void IRepository<T>.Update(T item, params Expression<Func<T, object>>[] fields)
        {
            Contract.Requires(item != null);
            Contract.Requires(fields != null);
            Contract.Requires(fields.Length > 0);
            Contract.ForAll(fields, i => i != null);
        }

        #endregion
    }
}